/*************************************************************************
 *
 *   file		: DBCReader.cs
 *   copyright		: (C) The WCell Team
 *   email		: info@wcell.org
 *   last changed	: $LastChangedDate: 2009-02-16 04:30:51 +0000 (Mon, 16 Feb 2009) $
 *   last author	: $LastChangedBy: ralekdev $
 *   revision		: $Rev: 757 $
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *************************************************************************/

using System;
using System.Collections.Generic;
using System.IO;
using WCell.Constants;

namespace WCell.Core.DBC
{
    public class DBCReader<TEntry, TConverter>
        where TConverter : DBCRecordConverter<TEntry>, new()
    {
        public readonly Dictionary<int, TEntry> Entries;
		public readonly List<TEntry> EntryList;
        private readonly int m_recordSize;
        private readonly int m_recordCount;
        private readonly int m_fieldCount;
        private readonly string m_fileName;

        public DBCReader(string fileName)
        {
            if (!File.Exists(fileName))
            {
                throw new FileNotFoundException("The required DBC file \"" + fileName + "\" was not found.");
            }

            m_fileName = fileName;

            using (var fileStream = new FileStream(m_fileName, FileMode.Open, FileAccess.Read))
            {
                using (var binReader = new BinaryReader(fileStream))
                {
                    if (binReader.ReadUInt32() != 0x43424457) // WDBC
                        return;
                    m_recordCount = binReader.ReadInt32();
                    m_fieldCount = binReader.ReadInt32();
                    m_recordSize = binReader.ReadInt32();
                    int stringTableSize = binReader.ReadInt32();

                    binReader.BaseStream.Position = binReader.BaseStream.Length - stringTableSize;

                    byte[] stringTable = binReader.ReadBytes(stringTableSize);

                    Entries = new Dictionary<int, TEntry>(m_recordCount);
					EntryList = new List<TEntry>(m_recordCount);

                    using (var converter = new TConverter())
                    {
                        converter.Init(stringTable);
                        MapRecords(binReader, converter);
                    }
                }
            }
        }

        private void MapRecords(BinaryReader binReader, TConverter converter)
        {
			try
			{
				binReader.BaseStream.Position = 20;

				int id;
				for (int i = 0; i < m_recordCount; i++)
				{
					id = i;
					TEntry entry = converter.ConvertTo(binReader.ReadBytes(m_recordSize), ref id);
					Entries.Add(id, entry);
					EntryList.Add(entry);
				}
			}
			catch (Exception e)
			{
				throw new Exception("Error when reading DBC-file (Required client version: " + WCellInfo.RequiredVersion + ")", e);
			}
        }

        public TEntry this[int id]
        {
            get
            {
				TEntry entry;
                Entries.TryGetValue(id, out entry);
				return entry;
                //return default(TEntry);
            }
        }

        public TEntry this[uint id]
        {
            get { return this[(int)id]; }
        }

        public int RecordSize
        {
            get { return m_recordSize; }
        }

        public int FieldCount
        {
            get { return m_fieldCount; }
        }

        public string FileName
        {
            get { return m_fileName; }
        }
    }
}